package zzs.generalframework.util.core.sop;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import zzs.generalframework.util.common.exception.UtilException;
import zzs.generalframework.util.common.model.SopBodyConfig;
import zzs.generalframework.util.core.bytee.ByteUtils;
import zzs.generalframework.util.core.calendar.CalendarUtils;

/**
 * @title
 * @description
 * @project zzs-util
 * @package zzs.generalframework.util.core.sop
 * @author zzs
 * @date 2018年1月30日
 * @version 1.0
 */
public class SopBodyUtils
{

	private Logger logger = LoggerFactory.getLogger(SopBodyUtils.class);

	/**
	 * 解析报文体
	 * 
	 * @param byteArray
	 *            源字段数组<br>
	 * @param startPos
	 *            起始位置<br>
	 * @param sopBodyConfigList
	 *            SOP配置列表<br>
	 * @return 解析后的SOPBodyMap<br>
	 * @throws UtilException
	 */
	public Map<String, Object> sopBodyDecode(byte[] byteArray, int startPos, List<SopBodyConfig> sopBodyConfigList) throws UtilException
	{
		logger.info("====解析报文开始====");
		Map<String, Object> returnMap = null;
		try
		{
			if (sopBodyConfigList == null || sopBodyConfigList.size() == 0)
			{
				logger.info("无报文体配置");
			}
			else if (byteArray == null || byteArray.length < startPos)
			{
				logger.info("无可解析报文体");
			}
			else
			{
				returnMap = new HashMap<String, Object>();
				for (SopBodyConfig itemConfig : sopBodyConfigList)
				{
					String fieldName = itemConfig.getFieldName();
					startPos = decodeField(byteArray, startPos, fieldName, returnMap);
				}
			}
		}
		catch (Exception e)
		{
			throw new UtilException(e.getMessage());
		}

		logger.info("====解析报文结束====");
		return returnMap;
	}

	public byte[] sopBodyEncode(Map<String, Object> sopBodyMap, List<SopBodyConfig> sopBodyConfigList) throws UtilException
	{
		logger.info("====编码报文开始====");
		byte[] returnByteArray = null;
		ByteArrayOutputStream byteArrayOutputStream = null;
		try
		{
			if (sopBodyMap == null || sopBodyMap.size() == 0)
			{
				logger.info("无可编码报文体业务信息");
			}
			else if (sopBodyConfigList == null || sopBodyConfigList.size() == 0)
			{
				logger.info("无编码报文体配置信息");
			}
			else
			{
				byteArrayOutputStream = new ByteArrayOutputStream();
				for (SopBodyConfig itemConfig : sopBodyConfigList)
				{
					String fieldName = itemConfig.getFieldName();
					Object fieldValueObj = sopBodyMap.get(fieldName);
					byte[] fieldByteArray = encodeField(fieldName, fieldValueObj);
					byteArrayOutputStream.write(fieldByteArray);
				}
				returnByteArray = byteArrayOutputStream.toByteArray();
			}
		}
		catch (Exception e)
		{
			logger.error("编码报文时出现异常,异常原因:[{}]", e);
			throw new UtilException(e.getMessage());
		}
		finally
		{
			if (byteArrayOutputStream != null)
			{
				try
				{
					byteArrayOutputStream.close();
				}
				catch (IOException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

		logger.info("====编码报文结束====");
		return returnByteArray;
	}

	/**
	 * 解析字段
	 * 
	 * @param byteArray
	 *            源字节数组<br>
	 * @param startPos
	 *            起始位置<br>
	 * @param key
	 *            字段的key<br>
	 * @param sopBodyMap
	 *            存储解析后字段的map<br>
	 * @return 当前已解析到的位置,即下次起始位置<br>
	 * @throws UtilException
	 */
	private int decodeField(byte[] byteArray, int startPos, String key, Map<String, Object> sopBodyMap) throws UtilException
	{
		logger.info("====解析字段开始====");
		ByteArrayOutputStream byteArrayOutputStream = null;
		try
		{
			// 存储值的字节流
			byteArrayOutputStream = new ByteArrayOutputStream();
			// 记录的字段长度
			int fieldLength = 0;
			do
			{
				byte[] lengthByteArray = ByteUtils.cutByte(byteArray, startPos, 1);
				startPos += 1;
				fieldLength = lengthByteArray[0] & 0xff;
				// 字段实际长度
				int realLength = 0;
				if (fieldLength == 0xff)
				{
					realLength = 0xfa;
				}
				else
				{
					realLength = fieldLength;
				}
				byte[] tempByteArray = ByteUtils.cutByte(byteArray, startPos, realLength);
				startPos += realLength;
				byteArrayOutputStream.write(tempByteArray);
			}
			// 记录的字段长度如果为0xff代表当前字段超长
			while (fieldLength == 0xff);
			String value = ByteUtils.decodeByte2String(byteArrayOutputStream.toByteArray());
			if (sopBodyMap == null)
			{
				sopBodyMap = new HashMap<String, Object>();
			}
			sopBodyMap.put(key, value);
		}
		catch (IOException e)
		{
			logger.error("解析字段值时出现异常,异常原因:[{}]", e);
			throw new UtilException(e.getMessage());
		}
		finally
		{
			if (byteArrayOutputStream != null)
			{
				try
				{
					byteArrayOutputStream.close();
				}
				catch (IOException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		logger.info("====解析字段结束====");
		return startPos;
	}

	/**
	 * 编码字段
	 * 
	 * @throws UtilException
	 */
	private byte[] encodeField(String fieldName, Object fieldValueObj) throws UtilException
	{
		logger.info("====编码字段开始====");
		// 返回值
		byte[] returnByteArray = null;
		ByteArrayOutputStream byteArrayOutputStream = null;
		try
		{
			// 存储一个字段的字节数组
			byte[] fieldByteArray = null;
			byteArrayOutputStream = new ByteArrayOutputStream();
			// 字段值的字符串表现形式
			String fieldValueStr = null;
			if (fieldValueObj == null)
			{
				fieldValueStr = "";
			}
			else if (fieldValueObj instanceof Date)
			{
				fieldValueStr = CalendarUtils.convertDate2String((Date) fieldValueObj);
			}
			else if (fieldValueObj instanceof byte[])
			{
				fieldValueStr = ((byte[]) fieldValueObj).toString();
			}
			else
			{
				fieldValueStr = String.valueOf(fieldValueObj);
			}
			// 字段值字节数组
			byte[] fieldValueByteArray = fieldValueStr.getBytes("UTF-8");
			// 字段值字节数组长度
			int fieldValueByteArrayLength = fieldValueByteArray.length;
			for (int startPos = 0; startPos < fieldValueByteArrayLength;)
			{
				byte[] tempLengthByteArray = new byte[1];
				byte[] tempValueByteArray = null;
				// 存储本次需处理的字节数组
				int curLength = fieldValueByteArrayLength - startPos;
				if (curLength > 0xfa)
				{
					curLength = 0xff;
					tempValueByteArray = new byte[250];
				}
				else
				{
					tempValueByteArray = new byte[curLength];
				}
				tempLengthByteArray[0] = new Integer(curLength).byteValue();
				tempValueByteArray = ByteUtils.cutByte(fieldValueByteArray, startPos, tempValueByteArray.length);
				byteArrayOutputStream.write(tempLengthByteArray);
				byteArrayOutputStream.write(tempValueByteArray);
				startPos += 0xfa;
			}
			returnByteArray = byteArrayOutputStream.toByteArray();
		}
		catch (Exception e)
		{
			logger.error("编码字段出现异常,异常原因:[{}]", e);
			throw new UtilException(e.getMessage());
		}
		finally
		{
			if (byteArrayOutputStream != null)
			{
				try
				{
					byteArrayOutputStream.close();
				}
				catch (IOException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		logger.info("====编码字段结束====");
		return returnByteArray;
	}

}
